import {isArray, isDef, isObject, isPlainObject} from "../../shared/util";
import {Dep} from "./dep";
import {observe} from "./observer";

/**
 * 向 target 添加 key, 向其设置 value
 * @param target
 * @param key
 * @param value
 */
export function def (target, key, value) {
    Object.defineProperty(
        target,
        key,
        {
            enumerable: true,
            configurable: true,
            writable: false,
            value: value
        }
    );
}

/**
 * 为 target 设置 key
 * @param target
 * @param key
 * @param value
 */
export function set (target, key, value) {
    defineReactive(target, key, value);
}

/**
 * 从 target 删除 key
 * @param target
 * @param key
 */
export function del (target, key) {
    delete target[key];
}

/**
 * 对 target[key] 进行的 set, get 动作进行订阅发布
 * @param target
 * @param key
 * @param defaultValue
 */
export function defineReactive (target, key, defaultValue) {
    // 获取默认值
    defaultValue = isDef(defaultValue)
        ? defaultValue
        : target[key];
    // 引用类型
    let valueObserver = null;
    if (isObject(defaultValue) || isArray(defaultValue)) {
        valueObserver = observe(defaultValue);
    }
    // // 基础类型
    // else {
    let value = defaultValue;
    const descriptor = Object.getOwnPropertyDescriptor(target, key);
    const setter = descriptor.set;
    const getter = descriptor.get;
    const dep = new Dep();
    Object.defineProperty(
        target,
        key,
        {
            enumerable: true,
            configurable: true,
            set: function set (newValue) {
                const oldValue = getter ? getter.call(target) : value;
                if (oldValue !== newValue) {
                    setter ? setter.call(target, newValue) : undefined;
                    value = newValue;
                    // 如果 valueObserver 存在
                    // 说明 value 值是对象或数组，需要重新观察
                    if (isDef(valueObserver)) {
                        valueObserver = observe(value);
                    }
                    dep.notify();
                }
            },
            get: function get () {
                const val = getter ? getter.call(target) : value;
                if (isDef(Dep.currentWatcher)) {
                    dep.collect();
                    // 如果 valueObserver 存在
                    // 需要为该对象或该数组添加 watcher 依赖
                    // 用以该对象或数组内值更新时，利用 watcher 更新
                    if (isDef(valueObserver)) {
                        valueObserver.dep.collect();
                    }
                }
                return val;
            }
        }
    );
    // }
}
